-
Notifications
You must be signed in to change notification settings - Fork 12
Allow specifying path to schema-sync folder with SCHEMA_SYNC_PATH #72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This pull request adds support for customizing the path to the schema-sync folder via the SCHEMA_SYNC_PATH environment variable. By default, it continues to use (Directus root)/schema-sync.
Changes:
- Introduced
SCHEMA_SYNC_PATHenvironment variable to allow customization of the schema-sync folder location - Refactored
ExportHelperstatic class into instance-basedExportMetaclass to support configurable paths - Updated all components (
SchemaExporter,CollectionExporter,ExportManager) to accept and use the configurable path
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| src/exportMeta.ts | New file containing the ExportMeta class with path configuration support, moved from ExportHelper in utils.ts |
| src/utils.ts | Removed ExportHelper class, extracted fileExists as a standalone utility function |
| src/types.ts | Added optional path parameter to CollectionExporterOptions |
| src/index.ts | Updated to instantiate ExportMeta with SCHEMA_SYNC_PATH and pass path to all exporters |
| src/exportManager.ts | Added path parameter to constructor and passes it to collection exporters |
| src/schemaExporter.ts | Added path option to constructor and uses ExportMeta for directory resolution |
| src/collectionExporter.ts | Updated to use ExportMeta with configurable path instead of static ExportHelper |
| src/updateManager.ts | Removed unused ExportHelper import |
| README.md | Added documentation for SCHEMA_SYNC_PATH environment variable and cleaned up trailing whitespace |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public schemaDir: string; | ||
|
|
||
| constructor(schemaDir?: string) { | ||
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | ||
| } |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation detected. The code uses spaces instead of tabs, which is inconsistent with the rest of the file. Lines 6-10 should use tabs for indentation to match the project's style.
| public schemaDir: string; | |
| constructor(schemaDir?: string) { | |
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | |
| } | |
| public schemaDir: string; | |
| constructor(schemaDir?: string) { | |
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | |
| } |
| public schemaDir: string; | ||
|
|
||
| constructor(schemaDir?: string) { | ||
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | ||
| } | ||
|
|
||
| get dataDir() { | ||
| return resolve(this.schemaDir, 'data'); | ||
| } | ||
|
|
||
| get hashFile() { | ||
| return resolve(this.schemaDir, 'hash.txt'); | ||
| } | ||
|
|
||
| async updateExportMeta() { | ||
| const hasher = createHash('sha256'); | ||
| const files = await readdir(this.dataDir); | ||
| for (const file of files) { | ||
| if (file.endsWith('.json')) { | ||
| const json = await readFile(`${this.dataDir}/${file}`, { encoding: 'utf8' }); | ||
| hasher.update(json); | ||
| } | ||
| } | ||
| const hash = hasher.digest('hex'); | ||
|
|
||
| const { hash: previousHash } = await this.getExportMeta() || {}; | ||
|
|
||
| // Only update hash file if it has changed | ||
| if (hash === previousHash) return false; | ||
|
|
||
| const ts = utcTS(); | ||
| const txt = hash + '@' + ts; | ||
|
|
||
| await writeFile(this.hashFile, txt); | ||
| return { | ||
| hash, | ||
| ts, | ||
| }; | ||
| } | ||
|
|
||
| async getExportMeta() { | ||
| try { | ||
| const content = await readFile(this.hashFile, { encoding: 'utf8' }); | ||
| const [hash, ts] = content.split('@'); | ||
|
|
||
| if (hash && ts && new Date(ts).toString() !== 'Invalid Date') { | ||
| return { | ||
| hash, | ||
| ts, | ||
| }; | ||
| } | ||
| } catch { | ||
| // ignore | ||
| } | ||
| return null; | ||
| } |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation detected. The code uses spaces instead of tabs. The entire class body (lines 20-61) should use tabs for indentation to match the project's style.
| public schemaDir: string; | |
| constructor(schemaDir?: string) { | |
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | |
| } | |
| get dataDir() { | |
| return resolve(this.schemaDir, 'data'); | |
| } | |
| get hashFile() { | |
| return resolve(this.schemaDir, 'hash.txt'); | |
| } | |
| async updateExportMeta() { | |
| const hasher = createHash('sha256'); | |
| const files = await readdir(this.dataDir); | |
| for (const file of files) { | |
| if (file.endsWith('.json')) { | |
| const json = await readFile(`${this.dataDir}/${file}`, { encoding: 'utf8' }); | |
| hasher.update(json); | |
| } | |
| } | |
| const hash = hasher.digest('hex'); | |
| const { hash: previousHash } = await this.getExportMeta() || {}; | |
| // Only update hash file if it has changed | |
| if (hash === previousHash) return false; | |
| const ts = utcTS(); | |
| const txt = hash + '@' + ts; | |
| await writeFile(this.hashFile, txt); | |
| return { | |
| hash, | |
| ts, | |
| }; | |
| } | |
| async getExportMeta() { | |
| try { | |
| const content = await readFile(this.hashFile, { encoding: 'utf8' }); | |
| const [hash, ts] = content.split('@'); | |
| if (hash && ts && new Date(ts).toString() !== 'Invalid Date') { | |
| return { | |
| hash, | |
| ts, | |
| }; | |
| } | |
| } catch { | |
| // ignore | |
| } | |
| return null; | |
| } | |
| public schemaDir: string; | |
| constructor(schemaDir?: string) { | |
| this.schemaDir = resolve(process.cwd(), schemaDir ?? 'schema-sync') | |
| } | |
| get dataDir() { | |
| return resolve(this.schemaDir, 'data'); | |
| } | |
| get hashFile() { | |
| return resolve(this.schemaDir, 'hash.txt'); | |
| } | |
| async updateExportMeta() { | |
| const hasher = createHash('sha256'); | |
| const files = await readdir(this.dataDir); | |
| for (const file of files) { | |
| if (file.endsWith('.json')) { | |
| const json = await readFile(`${this.dataDir}/${file}`, { encoding: 'utf8' }); | |
| hasher.update(json); | |
| } | |
| } | |
| const hash = hasher.digest('hex'); | |
| const { hash: previousHash } = await this.getExportMeta() || {}; | |
| // Only update hash file if it has changed | |
| if (hash === previousHash) return false; | |
| const ts = utcTS(); | |
| const txt = hash + '@' + ts; | |
| await writeFile(this.hashFile, txt); | |
| return { | |
| hash, | |
| ts, | |
| }; | |
| } | |
| async getExportMeta() { | |
| try { | |
| const content = await readFile(this.hashFile, { encoding: 'utf8' }); | |
| const [hash, ts] = content.split('@'); | |
| if (hash && ts && new Date(ts).toString() !== 'Invalid Date') { | |
| return { | |
| hash, | |
| ts, | |
| }; | |
| } | |
| } catch { | |
| // ignore | |
| } | |
| return null; | |
| } |
|
|
||
|
|
||
| export function utcTS(isoTimestamp: string = new Date().toISOString()) { | ||
| return isoTimestamp.replace('T', ' ').replace(/\.\d*Z/, ''); |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent indentation detected. The function uses spaces instead of tabs. Line 66 should use tabs for indentation to match the project's style.
| return isoTimestamp.replace('T', ' ').replace(/\.\d*Z/, ''); | |
| return isoTimestamp.replace('T', ' ').replace(/\.\d*Z/, ''); |
| constructor( | ||
| protected path: string, | ||
| protected logger: ApiExtensionContext['logger'] | ||
| ) { } |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra whitespace in the constructor body. The closing brace should be on the line after the constructor parameters without extra whitespace or tabs before it.
| ) { } | |
| ) {} |
| query?: Pick<Query, 'filter' | 'sort' | 'limit'>; | ||
|
|
||
| // Path to the export folder | ||
| path?: string, |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing trailing comma after the path property. Add a comma for consistency with the project's code style and to prevent potential issues when adding more properties.
| path?: string, | |
| path?: string; |
|
|
||
| constructor(protected logger: ApiExtensionContext['logger']) {} | ||
| constructor( | ||
| protected path: string, |
Copilot
AI
Jan 11, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The parameter should accept string | undefined instead of just string. The value env.SCHEMA_SYNC_PATH being passed can be undefined when the environment variable is not set, which should be a valid scenario based on the documentation showing the default value.
| protected path: string, | |
| protected path: string | undefined, |
Add
SCHEMA_SYNC_PATHenvironment variable allowing to specify/customize the path toschema-sync. By default :(Directus root)/schema-syncNote : Initially, I planned to add a global cli option
--path, but the current implementation with both global and command-scoped variables required too much refactoring.